import web3 from "web3";
import store from "@/store";
import { providers } from "ethers";
import Muliticall from "ethers-multicall";
import { WalletList } from "@/utils/connect";
import { ERC20, SWAP, PANCAKE, PANCAKE_PAIR, ARATAR_NFT } from "@/utils/abi";
import masterchefABIV1 from "@/assets/abi/masterchefV1.json";
import { maxAmount, isNativeToken, getProxyContract } from "@/config/config";
import { decimals2Amount, amount2Decimals } from "@/utils/number";
import showLoading from "@/components/loading";
import { confirmLater } from "@/utils/helper";
import { getTSEPrice, getGasPrice, addNFT } from "@/api/core";
import {
  TokenAmount,
  Fetcher,
  Pair,
  Route,
  Trade,
  TradeType,
  Percent,
  JSBI,
} from "@pancakeswap/sdk";
import { JsonRpcProvider } from "@ethersproject/providers";
import BigNumber from "bignumber.js";
const provider = new JsonRpcProvider("https://bsc-dataseed1.binance.org/");
const ROUTER_ADDRESS = "0xBeB43fbb2f7AEA8AC904975816BB1b4cA9f4D9c5";
const NFT_ADDRESS = "0x58c9ac8791bdebe2baaf7bd50074609fc72935e2";
import { File, NFTStorage } from "@/utils/nftStorage";
import { farms } from "@/utils/farms";
import { getTokenByAddress } from "@/utils/token";
import {
  ChainId,
  GelatoLimitOrders,
  GelatoStopLimitOrders,
  utils,
} from "@gelatonetwork/limit-orders-lib";

export const NFT_STORAGE_TOKEN =
  "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJkaWQ6ZXRocjoweGQ0RWVlNmVEOTE1OTVGRjFlMzYzYTk3NzY3RUU5QzYxM2Q5NzNmRGEiLCJpc3MiOiJuZnQtc3RvcmFnZSIsImlhdCI6MTY1MzQ5NzI1NjEzOSwibmFtZSI6InRvbnkifQ.U7rHAFqcuqvCY2rXoF0p2DL9bwPJ--Rb0yiyhppPkYc";
export const BIG_ZERO = new BigNumber(0);
export const BIG_ONE = new BigNumber(1);
export const BIG_TWO = new BigNumber(2);
export const BIG_NINE = new BigNumber(9);
export const BIG_TEN = new BigNumber(10);

export let myWallet = null;

export const getWallet = (code) => {
  const wallet = WalletList.filter((item) => {
    return item.code === code;
  });
  return (wallet && wallet[0]) || {};
};

export const loadTSEPrice = async () => {
  const price = await getTSEPrice();
  store.commit("SET_PRICE", price);
  setTimeout(() => {
    getTSEPrice();
  }, 10 * 1000);
};

export const loadGasPrice = async () => {
  const price = await getGasPrice();
  store.commit("SET_GASPRICE", price);
  setTimeout(() => {
    loadGasPrice();
  }, 10 * 1000);
};

export const tryConnect = async (chainCode, wallet, connect) => {
  if (!connect) return;

  const { account, sdk } = await connect(chainCode);
  if (sdk) {
    sdk.currentProvider.on("accountsChanged", () => {
      console.log("accountsChanged");
    });
    sdk.currentProvider.on("chainChanged", () => {
      console.log("chainChanged");
    });
    sdk.currentProvider.on("disconnect", () => {
      console.log("disconnect");
    });
    myWallet = sdk;
    const provider = new providers.Web3Provider(sdk.eth.currentProvider);
    store.commit("SET_CHAINCODE", chainCode);
    store.commit("SET_WALLET", wallet);
    store.commit("SET_SIGNER", provider.getSigner());
    store.commit("SET_ACCOUNT", account);
    const price = await getGasPrice();
    store.commit("SET_GASPRICE", price);
    return account;
  }
};

export const init = async () => {
  const { chainCode, wallet, account } = store.state;
  if (!chainCode || !wallet || !account) return;

  const { connect } = getWallet(wallet);
  await tryConnect(chainCode, wallet, connect);
};

export const sendApproveTo = async (address, type, amount, decimals) => {
  try {
    const contract = new myWallet.eth.Contract(ERC20, address);
    const { account, chainCode } = store.state;
    const tokenApprovalAddress = getProxyContract(chainCode);
    amount = type === "1" ? maxAmount : amount2Decimals(amount, +decimals);
    return await contract.methods.approve(tokenApprovalAddress, amount).send({
      from: account,
    });
  } catch (e) {
    console.log("sendApproveTo error", e);
    return null;
  }
};

export const getBalance = async (token) => {
  const { account, chainCode } = store.state;
  let balance = 0,
    allowance = 0;
  if (!account) {
    return {
      balance,
      allowance,
    };
  }
  const tokenApprovalAddress = getProxyContract(chainCode);
  const { address, decimals } = token;
  if (isNativeToken(address)) {
    balance = await myWallet.eth.getBalance(account);
  } else {
    const contract = new myWallet.eth.Contract(ERC20, address);
    balance = await contract.methods.balanceOf(account).call();
    allowance = tokenApprovalAddress ? await contract.methods.allowance(account, tokenApprovalAddress).call() : 0;
  }
  return {
    balance: decimals2Amount(balance, +decimals),
    allowance: decimals2Amount(allowance, +decimals),
  };
};

export const getBalancebyMulticall = async (tokenList) => {
  const { account } = store.state;
  const ethcallProvider = new Muliticall.Provider(provider, 56);
  await ethcallProvider.init();
  const multicall = [];
  for (let i = 0; i < tokenList.length; i++) {
    const { address } = tokenList[i];
    if (address === "0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE") {
      multicall.push(ethcallProvider.getEthBalance(account));
    } else {
      const contract = new Muliticall.Contract(address, ERC20);
      multicall.push(contract.balanceOf(account));
    }
  }
  const result = await ethcallProvider.all(multicall);
  return result.map((item, i) => {
    const { decimals } = tokenList[i];
    const amount = web3.utils.hexToNumberString(item);
    const balance = +amount === 0 ? 0 : decimals2Amount(amount, decimals);
    tokenList[i].balance = +balance;
    return tokenList[i];
  });
};

export const getBalanceOf = async (type) => {
  const { from, to } = store.state;
  const token = type === "from" ? from : to;
  const { balance, allowance } = await getBalance(token);
  token.balance = balance;
  token.allowance = allowance;
  store.commit(type === "from" ? "SET_FROM" : "SET_TO", token);
  console.log("getBalanceOf", type, balance, allowance);
};

export const getTotalSupply = async (token) => {
  const { account } = store.state;
  let totalSupply = 0;
  if (!account) {
    return totalSupply;
  }
  const { address, decimals } = token;
  const contract = new myWallet.eth.Contract(ERC20, address);
  totalSupply = await contract.methods.totalSupply().call();
  return decimals2Amount(totalSupply, +decimals);
};

export const sendTransaction = async (txObject, extra) => {
  const {
    data
  } = txObject;
  const {
    aggregator,
    inTokenSymbol,
    inTokenAddress,
    inAmountNum,
    inAmount,
    outTokenSymbol,
    outTokenAddress,
    outAmountNum,
  } = extra;
  const { account, chainCode } = store.state;
  const tokenApprovalAddress = getProxyContract(chainCode);
  const instanct = showLoading({
    text: `Swaping ${inAmountNum} ${inTokenSymbol} for ${outAmountNum} ${outTokenSymbol}`,
    name: aggregator,
  });
  try {
    const contract = new myWallet.eth.Contract(SWAP, tokenApprovalAddress);
    const value = isNativeToken(inTokenAddress) ? inAmount : 0;
    debugger
    const transactionHash = await confirmLater(
      contract.methods.swap(inTokenAddress, outTokenAddress, inAmount, aggregator, data).send({
        from: account,
        value
      })
    );
    if (transactionHash) {
      instanct.change({
        message: "submit",
        chainCode,
        hash: transactionHash,
        status: "success",
      });
    }
  } catch (e) {
    console.log(e);
    instanct.change({
      message: e.message,
      chainCode,
      status: "rejected",
    });
  }
};

export const swap = async (res) => {
  const { tokenIn, tokenOut, amount, slippage } = res;
  const amountIn = amount2Decimals(amount, 18);
  const { account } = store.state;
  const pair = await Fetcher.fetchPairData(tokenIn, tokenOut, provider);
  const route = await new Route([pair], tokenIn);
  const trade = await new Trade(
    route,
    new TokenAmount(tokenIn, new BigNumber(amountIn)),
    TradeType.EXACT_INPUT
  );
  const slippageTolerance = new Percent(slippage, "1000");
  const amountOutMin = trade.minimumAmountOut(slippageTolerance).raw.toString();
  const path = [tokenIn.address, tokenOut.address];
  const to = account;
  const deadline = Math.floor(Date.now() / 1000) + 60 * 20;
  const pancakeswap = new myWallet.eth.Contract(PANCAKE, ROUTER_ADDRESS);
  const tx = await pancakeswap.methods
    .swapExactTokensForTokens(amountIn, amountOutMin, path, to, deadline)
    .send({
      from: account,
      value: isNativeToken(tokenIn.address) ? inAmount : 0,
    });
  console.log("addLiquidity", tx);
};

export const getPairInfo = async (tokenA, tokenB) => {
  const pair = await getPair(tokenA, tokenB);
  pair._token0Price = pair.token0Price.toSignificant(6);
  pair._token1Price = pair.token1Price.toSignificant(6);
  const res = await getLiquidityBalance(pair, tokenA, tokenB, true);
  Object.assign(pair, res);
  return pair;
};

export const getPair = async (tokenA, tokenB) => {
  return await Fetcher.fetchPairData(tokenA, tokenB, provider);
};

export function calculateSlippageAmount(value, slippage) {
  if (slippage < 0 || slippage > 10000) {
    throw Error(`Unexpected slippage value: ${slippage}`);
  }
  return JSBI.divide(JSBI.multiply(value.raw, JSBI.BigInt(10000 - slippage)), JSBI.BigInt(10000));
}

export function calculatePercentLiquidity(value, percent) {
  if (percent < 0 || percent > 100) {
    throw Error(`Unexpected liquidity value: ${percent}`);
  }
  return JSBI.divide(JSBI.multiply(value.raw, JSBI.BigInt(100 - percent)), JSBI.BigInt(100));
}

/*
{ internalType: "address", name: "tokenA", type: "address" },
{ internalType: "address", name: "tokenB", type: "address" },
{ internalType: "uint256", name: "amountADesired", type: "uint256" },
{ internalType: "uint256", name: "amountBDesired", type: "uint256" },
{ internalType: "uint256", name: "amountAMin", type: "uint256" },
{ internalType: "uint256", name: "amountBMin", type: "uint256" },
{ internalType: "address", name: "to", type: "address" },
{ internalType: "uint256", name: "deadline", type: "uint256" },
*/
export const addLiquidity = async (res) => {
  const { tokenA, tokenB, amount, slippage } = res;
  const { account, chainCode } = store.state;
  const instanct = showLoading({
    text: `Add Liquidity`,
  });
  try {
    const amountIn = amount2Decimals(amount, tokenA.decimals);
    const pair = await getPair(tokenA, tokenB);
    const amountADesired = new TokenAmount(tokenA, amountIn);
    const amountBDesired = pair.priceOf(tokenA).quote(amountADesired);
    const amountAMin = calculateSlippageAmount(amountADesired, slippage);
    const amountBMin = calculateSlippageAmount(amountBDesired, slippage);
    const to = account;
    const deadline = Math.floor(Date.now() / 1000) + 60 * 20;
    const pancakeswap = new myWallet.eth.Contract(PANCAKE, ROUTER_ADDRESS);
    const transactionHash = await confirmLater(
      pancakeswap.methods
        .addLiquidity(
          tokenA.address,
          tokenB.address,
          amountADesired.raw.toString(),
          amountBDesired.raw.toString(),
          amountAMin.toString(),
          amountBMin.toString(),
          to,
          deadline
        )
        .send({
          from: account,
          value: 0,
        })
    );
    if (transactionHash) {
      instanct.change({
        message: "submit",
        chainCode,
        hash: transactionHash,
        status: "success",
      });
    }
  } catch (e) {
    console.log(e);
    instanct.change({
      message: e.message,
      chainCode,
      status: "rejected",
    });
  }
};

export const getLiquidityBalance = async (pair, tokenA, tokenB, format) => {
  const address = Pair.getAddress(tokenA, tokenB);
  const { account } = store.state;
  if (!account) {
    return { totalSupply: null, userLiquidity: null };
  }
  const contract = new myWallet.eth.Contract(ERC20, address);
  // const decimals = await contract.methods.decimals().call();
  const _totalSupply = await contract.methods.totalSupply().call();
  const totalSupply = new TokenAmount(pair.liquidityToken, _totalSupply.toString());
  const _userLiquidity = await contract.methods.balanceOf(account).call();
  const userLiquidity = new TokenAmount(pair.liquidityToken, _userLiquidity.toString());
  // return decimals2Amount(balance, +decimals);
  const amountA = new TokenAmount(
    tokenA,
    pair.getLiquidityValue(tokenA, totalSupply, userLiquidity, false).raw
  );
  const amountB = new TokenAmount(
    tokenB,
    pair.getLiquidityValue(tokenB, totalSupply, userLiquidity, false).raw
  );
  if (format) {
    const _decimals = await contract.methods.decimals().call();
    const allowance = await contract.methods.allowance(account, ROUTER_ADDRESS).call();
    return {
      amountA: decimals2Amount(amountA.raw.toString(), tokenA.decimals),
      amountB: decimals2Amount(amountB.raw.toString(), tokenB.decimals),
      totalSupply: decimals2Amount(_totalSupply, _decimals),
      userLiquidity: decimals2Amount(_userLiquidity, _decimals),
      allowance: decimals2Amount(allowance, _decimals),
    };
  }
  return {
    amountA,
    amountB,
    totalSupply,
    userLiquidity,
  };
};

export const getLiquidityTotalSupply = async (pair, tokenA, tokenB) => {
  const address = Pair.getAddress(tokenA, tokenB);
  const { account } = store.state;
  if (!account) {
    return { totalSupply: null, userLiquidity: null };
  }
  const contract = new myWallet.eth.Contract(ERC20, address);
  const _totalSupply = await contract.methods.totalSupply().call();
  return new TokenAmount(pair.liquidityToken, _totalSupply.toString());
};

export const getLiquidityQuote = async (res) => {
  const { tokenA, tokenB, amount } = res;
  const amountIn = amount2Decimals(amount, tokenA.decimals);
  const pair = await getPair(tokenA, tokenB);
  const address = Pair.getAddress(tokenA, tokenB);
  const contract = new myWallet.eth.Contract(ERC20, address);
  const _totalSupply = await contract.methods.totalSupply().call();
  const _decimals = await contract.methods.decimals().call();
  const totalSupply = new TokenAmount(pair.liquidityToken, _totalSupply.toString());
  const amountA = new TokenAmount(tokenA, amountIn);
  const amountB = pair.priceOf(tokenA).quote(amountA);
  const liquidityMinted = pair.getLiquidityMinted(totalSupply, amountA, amountB);
  return {
    amountLP: decimals2Amount(liquidityMinted.raw.toString(), _decimals),
    amountB: decimals2Amount(amountB.raw.toString(), _decimals),
  };
};

export const sendLPApproveTo = async (address, type, amount, decimals) => {
  try {
    const contract = new myWallet.eth.Contract(ERC20, address);
    const { account } = store.state;
    amount = type === "1" ? maxAmount : amount2Decimals(amount, +decimals);
    return await contract.methods.approve(ROUTER_ADDRESS, amount).send({
      from: account,
    });
  } catch (e) {
    console.log("sendApproveTo error", e);
    return null;
  }
};

/*
{ internalType: "address", name: "tokenA", type: "address" },
{ internalType: "address", name: "tokenB", type: "address" },
{ internalType: "uint256", name: "liquidity", type: "uint256" },
{ internalType: "uint256", name: "amountAMin", type: "uint256" },
{ internalType: "uint256", name: "amountBMin", type: "uint256" },
{ internalType: "address", name: "to", type: "address" },
{ internalType: "uint256", name: "deadline", type: "uint256" },
*/
export const removeLiquidity = async (res) => {
  const { tokenA, tokenB, remove, slippage } = res;
  const { account, chainCode } = store.state;
  const instanct = showLoading({
    text: `Add Liquidity`,
  });
  try {
    const pair = await getPair(tokenA, tokenB);
    const { amountA, amountB, userLiquidity } = await getLiquidityBalance(pair, tokenA, tokenB);
    const percent = new Percent(remove, "100");
    const liquidity = new TokenAmount(
      pair.liquidityToken,
      percent.multiply(userLiquidity.raw).quotient
    );
    const _amountAMin = new TokenAmount(tokenA, percent.multiply(amountA.raw).quotient);
    const _amountBMin = new TokenAmount(tokenB, percent.multiply(amountB.raw).quotient);
    const amountAMin = calculateSlippageAmount(_amountAMin, slippage);
    const amountBMin = calculateSlippageAmount(_amountBMin, slippage);
    const to = account;
    const deadline = Math.floor(Date.now() / 1000) + 60 * 20;
    const pancakeswap = new myWallet.eth.Contract(PANCAKE, ROUTER_ADDRESS);
    const transactionHash = await confirmLater(
      pancakeswap.methods
        .removeLiquidity(
          tokenA.address,
          tokenB.address,
          liquidity.raw.toString(),
          amountAMin.toString(),
          amountBMin.toString(),
          to,
          deadline
        )
        .send({
          from: account,
          value: 0,
        })
    );
    if (transactionHash) {
      instanct.change({
        message: "submit",
        chainCode,
        hash: transactionHash,
        status: "success",
      });
    }
  } catch (e) {
    console.log(e);
    instanct.change({
      message: e.message,
      chainCode,
      status: "rejected",
    });
  }
};

export const createLimitOrder = async (res) => {
  const { from, to, amount, tolerance } = res;
  // Token to sell
  const inputToken = from.address;
  // Token to buy
  const outputToken = to.address;
  // Amount to sell
  const inputAmount = amount2Decimals(amount, from.decimals);
  // Minimum amount of outToken which the users wants to receive back
  const minReturn = amount2Decimals((amount * (100 - tolerance)) / 100, to.decimals);
  // await gelatoLimitOrders.approveTokenAmount(inputToken, inputAmount);
  const chainId = 56;
  const provider = new providers.Web3Provider(myWallet.eth.currentProvider);
  const signerOrProvider = provider.getSigner();
  const gelatoLimitOrders = new GelatoLimitOrders(chainId, signerOrProvider);

  const tx = await gelatoLimitOrders.submitLimitOrder(
    inputToken,
    outputToken,
    inputAmount,
    minReturn
  );
};

export const getOpenOrders = async () => {
  const { account } = store.state;
  const chainId = 56;
  const provider = new providers.Web3Provider(myWallet.eth.currentProvider);
  const signerOrProvider = provider.getSigner();
  const gelatoLimitOrders = new GelatoLimitOrders(chainId, signerOrProvider);
  const list = await gelatoLimitOrders.getOpenOrders(account);
  return list.map((item) => {
    const inputToken = getTokenByAddress(item.inputToken);
    item.inputTokenSymbol = inputToken.symbol;
    item.inputTokenIcon = inputToken.icon;
    item.inputAmount = decimals2Amount(item.inputAmount, inputToken.decimals);
    const outputToken = getTokenByAddress(item.outputToken);
    item.outputTokenSymbol = outputToken.symbol;
    item.outputTokenIcon = outputToken.icon;
    item.minReturn = decimals2Amount(item.minReturn, outputToken.decimals);
    return item;
  });
};

export const getOrders = async () => {
  const { account } = store.state;
  const chainId = 56;
  const provider = new providers.Web3Provider(myWallet.eth.currentProvider);
  const signerOrProvider = provider.getSigner();
  const gelatoLimitOrders = new GelatoLimitOrders(chainId, signerOrProvider);
  const list = await gelatoLimitOrders.getOrders(account);
  return list.map((item) => {
    const inputToken = getTokenByAddress(item.inputToken);
    item.inputTokenSymbol = inputToken.symbol;
    item.inputTokenIcon = inputToken.icon;
    item.inputAmount = decimals2Amount(item.inputAmount, inputToken.decimals);
    const outputToken = getTokenByAddress(item.outputToken);
    item.outputTokenSymbol = outputToken.symbol;
    item.outputTokenIcon = outputToken.icon;
    item.minReturn = decimals2Amount(item.minReturn, outputToken.decimals);
    return item;
  });
};

export const cancelLimitOrder = async (id) => {
  const chainId = 56;
  const provider = new providers.Web3Provider(myWallet.eth.currentProvider);
  const signerOrProvider = provider.getSigner();
  const gelatoLimitOrders = new GelatoLimitOrders(chainId, signerOrProvider);
  const order = await gelatoLimitOrders.getOrder(id);
  const tx = await gelatoLimitOrders.cancelLimitOrder(order);
  console.log(tx);
};

// export const stakeFarm = async (masterChefContract, pid, amount) => {
//   const gasPrice = getGasPrice()
//   const value = new BigNumber(amount).times(DEFAULT_TOKEN_DECIMAL).toString()

//   return masterChefContract.deposit(pid, value, { ...options, gasPrice })
// }

// export const unstakeFarm = async (masterChefContract, pid, amount) => {
//   const gasPrice = getGasPrice()
//   const value = new BigNumber(amount).times(DEFAULT_TOKEN_DECIMAL).toString()

//   return masterChefContract.withdraw(pid, value, { ...options, gasPrice })
// }

// export const harvestFarm = async (masterChefContract, pid) => {
//   const gasPrice = getGasPrice()

//   return masterChefContract.deposit(pid, '0', { ...options, gasPrice })
// }

// export const fetchToken = async (address) => {
//   const token = new myWallet.eth.Contract(ERC20, address);
//   const name = await token.methods.name().call();
//   const symbol = await token.methods.symbol().call();
//   const decimals = await token.methods.decimals().call();
//   return {
//     name,
//     symbol,
//     decimals,
//   };
// };

export const fetchLP = async (address, token, quoteToken) => {
  const { account } = store.state;
  const lp = new myWallet.eth.Contract(PANCAKE_PAIR, address);
  const totalSupply = await lp.methods.totalSupply().call();
  const balance = await lp.methods.balanceOf(account).call();
  const decimals = await lp.methods.decimals().call();
  const reserves = await lp.methods.getReserves().call();
  // Raw amount of token in the LP, including those not staked
  const tokenBalanceLP = decimals2Amount(reserves[0], token.decimals);
  const quoteTokenBalanceLP = decimals2Amount(reserves[1], quoteToken.decimals);
  return {
    lpTotalSupply: decimals2Amount(totalSupply, decimals),
    lpTokenBalanceMC: decimals2Amount(balance, decimals),
    tokenBalanceLP,
    quoteTokenBalanceLP,
  };
};

export const fetchFarms = async () => {
  const contract = new myWallet.eth.Contract(
    masterchefABIV1,
    "0x73feaa1eE314F8c655E354234017bE2193C9E24E"
  );
  // const poolLength = await contract.methods.poolLength().call();
  const totalAllocPoint = await contract.methods.totalAllocPoint().call();
  const list = [];
  const total = farms.length > 6 ? 6 : farms.length;
  for (var i = 0; i < total; i++) {
    const farm = farms[i];
    const { v1pid, token, quoteToken } = farm;
    const info = await contract.methods.poolInfo(v1pid).call();
    const lp = await fetchLP(info.lpToken, token, quoteToken);
    console.log("lp", farm, info, lp);
    list.push({
      ...farm,
      ...info,
      ...lp,
    });
  }
  const result = list.map((item) => {
    const {
      tokenBalanceLP,
      quoteTokenBalanceLP,
      lpTokenBalanceMC,
      lpTotalSupply,
      token,
      quoteToken,
    } = item;
    const tokenDecimals = token.decimals;
    const quoteTokenDecimals = quoteToken.decimals;

    // Ratio in % of LP tokens that are staked in the MC, vs the total number in circulation
    const lpTokenRatio = new BigNumber(lpTokenBalanceMC).div(new BigNumber(lpTotalSupply));

    // Raw amount of token in the LP, including those not staked
    const tokenAmountTotal = new BigNumber(tokenBalanceLP).div(BIG_TEN.pow(tokenDecimals));
    const quoteTokenAmountTotal = new BigNumber(quoteTokenBalanceLP).div(
      BIG_TEN.pow(quoteTokenDecimals)
    );

    // Amount of quoteToken in the LP that are staked in the MC
    const quoteTokenAmountMc = quoteTokenAmountTotal.times(lpTokenRatio);

    // Total staked in LP, in quote token value
    const lpTotalInQuoteToken = quoteTokenAmountMc.times(BIG_TWO);

    const allocPoint = item.allocPoint ? new BigNumber(item.allocPoint) : BIG_ZERO;
    const poolWeight = totalAllocPoint ? allocPoint.div(new BigNumber(totalAllocPoint)) : BIG_ZERO;

    return {
      ...item,
      lpTotalInQuoteToken: lpTotalInQuoteToken.toJSON(),
      tokenPriceVsQuote: quoteTokenAmountTotal.div(tokenAmountTotal).toJSON(),
      poolWeight: poolWeight.toJSON(),
      multiplier: `${allocPoint.div(100).toString()}X`,
    };
  });
  console.log("fetchFarms", result);
  return result;
};

export const upload = async (ImageData, MetaData) => {
  try {
    const storage = new NFTStorage({ token: NFT_STORAGE_TOKEN });
    const imageFile = new File([ImageData], `nft${new Date().getTime()}.png`, {
      type: "image/png",
    });
    const { name, description, properties } = MetaData;
    const metadata = await storage.store({
      name,
      description,
      image: imageFile,
      properties,
    });
    const { url, data } = metadata || {};
    const { image } = data || {};
    const { href } = image || {};
    return {
      uri: url.replace("ipfs://", "https://ipfs.io/ipfs/"),
      data: {
        name,
        description,
        image: href.replace("ipfs://", "https://ipfs.io/ipfs/"),
        properties,
      },
    };
  } catch (e) {
    console.log("upload error", e);
    return "";
  }
};

export const safeMint = async (ImageData, MetaData, Price, reload) => {
  const { account, chainCode } = store.state;
  const instanct = showLoading({
    text: `SafeMint for you`,
  });
  try {
    const metadata = await upload(ImageData, MetaData);
    console.log("metadata3", metadata);
    const { uri } = metadata;
    console.log("uri", uri);
    if (!uri) return;
    const contract = new myWallet.eth.Contract(ARATAR_NFT, NFT_ADDRESS);
    const transactionHash = await confirmLater(
      contract.methods.safeMint(account, uri).send({
        from: account,
      }),
      async () => {
        setTimeout(async () => {
          if (transactionHash) {
            instanct.change({
              message: "submit",
              chainCode,
              hash: transactionHash,
              status: "success",
            });
          }
          await addNFT(transactionHash, metadata.data, Price);
          reload && reload();
        }, 2000);
      }
    );
  } catch (e) {
    console.log(e);
    instanct.change({
      message: e.message,
      chainCode,
      status: "rejected",
    });
  }
};
